package icu.bughub.app.webview

import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.webkit.ValueCallback
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.viewinterop.AndroidView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

@SuppressLint("SetJavaScriptEnabled")
@Composable
fun WebView(state: WebViewState) {

    var webView by remember {
        mutableStateOf<WebView?>(null)
    }

    //webview变化或者 state 变化时重新订阅流数据
    LaunchedEffect(webView, state) {
        with(state) {
            //订阅流数据
            webView?.handleEvent()
        }
    }

    AndroidView(factory = { context ->
        WebView(context).apply {

            webChromeClient = object : WebChromeClient() {
                override fun onReceivedTitle(view: WebView?, title: String?) {
                    state.pageTitle = title
                }
            }

            webViewClient = object : WebViewClient() {
                override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                    super.onPageStarted(view, url, favicon)
                    state.pageTitle = null
                }

                override fun onPageFinished(view: WebView?, url: String?) {
                    super.onPageFinished(view, url)
                    state.pageTitle = view?.title
                }
            }

            with(settings) {
                javaScriptEnabled = true
                domStorageEnabled = true
                setSupportZoom(true)
            }
            //evaluateJavascript { }
        }.also {
            webView = it
        }
    }) { webView ->
        //webView.loadUrl("https://mobile.jd.com")
        when (val content = state.content) {
            is WebContent.Url -> {
                val url = content.url
                //url不为空或者当前的webView加载的url不相同
                if (url.isNotEmpty() && url != webView.url) {
                    webView.loadUrl(content.url)
                }
            }

            is WebContent.Data -> {
                webView.loadDataWithBaseURL(
                    content.baseUrl,
                    content.data,
                    "text/html",
                    "utf-8",
                    ""
                )
            }
        }

    }
}

//声明两种内容
sealed class WebContent() {
    data class Url(val url: String) : WebContent()
    data class Data(val data: String, val baseUrl: String? = null) : WebContent()

}

class WebViewState(private val coroutineScope: CoroutineScope, webContent: WebContent) {
    // 网页内容 url 或者 data(html 内容)
    var content by mutableStateOf(webContent)

    //  todo 遗留问题  调用范围问题? 不能设置为private 应该怎么办
    var pageTitle: String? by mutableStateOf(null)
        internal set  //内部的意思


    fun test() {

    }

    private enum class EventType {
        EVALUATE_JAVASCRIPT, //执行js方法
    }

    //共享流的数据类型
    private class WebViewEvent(
        val type: EventType,
        val args: String? = null,
        val resultCallback: ValueCallback<String>? = null
    )

    //共享流
    private val events: MutableSharedFlow<WebViewEvent> = MutableSharedFlow()

    suspend fun WebView.handleEvent(): Nothing = withContext(Dispatchers.Main) {
        events.collect { event ->
            when (event.type) {
                EventType.EVALUATE_JAVASCRIPT -> {
                    event.args?.let {
                        evaluateJavascript(it, event.resultCallback)
                    }
                }
            }
        }
    }

    //执行js方法
    fun evaluateJavascript(script: String, resultCallback: ValueCallback<String>? = null) {
        val event = WebViewEvent(EventType.EVALUATE_JAVASCRIPT, script, resultCallback)
        coroutineScope.launch {
            events.emit(event) //推送流
        }
    }

}

@Composable
fun rememberWebViewState(coroutineScope: CoroutineScope = rememberCoroutineScope(), url: String) =
    remember(key1 = url) {
        WebViewState(coroutineScope, WebContent.Url(url = url))
    }

@Composable
fun rememberWebViewState(
    coroutineScope: CoroutineScope = rememberCoroutineScope(),
    data: String,
    baseUrl: String = "",
) =
    remember(key1 = data, key2 = baseUrl) {
        WebViewState(
            coroutineScope = coroutineScope,
            WebContent.Data(data = data, baseUrl = baseUrl)
        )
    }


